package org.nutz.lang.stream;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;

import org.nutz.lang.Encoding;
import org.nutz.lang.Lang;
import org.nutz.lang.Streams;

public class StreamBuffer extends InputStream {

	private static class OutputStreamBuffer extends OutputStream {
		private ArrayList<byte[]> bytes = new ArrayList<byte[]>();
		private int width = 1024;
		private int index = 0;
		private int cursor = 0;

		@Override
		public void write(int b) throws IOException {
			if (cursor >= width)
				index++;
			byte[] row = bytes.size() > index ? bytes.get(index) : null;
			if (null == row) {
				row = new byte[width];
				bytes.add(row);
				cursor = 0;
			}
			row[cursor++] = (byte)b;
		}

		private int size() {
			return index > 0 ? width * (index - 1) + cursor : cursor;
		}

	}

	private OutputStreamBuffer buffer = new OutputStreamBuffer();
	private int index = 0;
	private int cursor = 0;

	public OutputStream getBuffer() {
		return buffer;
	}

	public void write(int b) throws IOException {
		buffer.write(b);
	}

	@Override
	public int read() throws IOException {
		if (cursor > buffer.width) {
			index++;
			cursor = 0;
		}
		if (index > buffer.index)
			return -1;
		if (index < buffer.bytes.size()) {
			byte[] cs = buffer.bytes.get(index);
			if (cursor < buffer.cursor)
				return cs[cursor++];
		}
		return -1;
	}

	@Override
	public int available() throws IOException {
		return buffer.size();
	}

	@Override
	public synchronized void reset() throws IOException {
		index = 0;
		cursor = 0;
	}

	@Override
	public String toString() {
		try {
			return toString(Encoding.defaultEncoding());
		}
		catch (IOException e) {
			throw Lang.wrapThrow(e);
		}
	}

	public String toString(String charset) throws IOException {
		index = 0;
		cursor = 0;
		StringBuilder sb = new StringBuilder();
		StringOutputStream sos = new StringOutputStream(sb, charset);
		byte c;
		while ((c = (byte) this.read()) != -1)
			sos.write(c);
		Streams.safeFlush(sos);
		Streams.safeClose(sos);
		return sb.toString();
	}

}
